package org.noote.libs.computervision.detection.line;

import java.util.ArrayList;

import org.noote.libs.computervision.buffer.Buffer8I;
import org.noote.libs.computervision.math.Segment2D;


/**
* Hough Transform for line detection
* 
* @author Xavier Philippeau
* http://www.developpez.net/forums/d495285/autres-langages/algorithmes/contribuez/image-detecteur-ligne-hough/
*
*/

public class HoughDetection {
	// image size
	private int iWidth=0, iHeight=0;

	// max Rho walue (= length of the diagonal)
	private double maxRho=0;

	// size of the accumulators array
	private int maxIndexTheta=0,maxIndexRho=0;
	
	// accumulators array
	private int[][] acc = null;
	
	private class LineSpace
	{
		private int acc;
		private double rho, theta;
		private double a, b;
	};
	
	private ArrayList<LineSpace> detectedLines = new ArrayList<LineSpace>();
	
	public boolean createHoughAccumulator(int width,int height)
	{
		if(width != this.iWidth || height != this.iHeight)
		{
			this.iWidth=width;
			this.iHeight=height;
	
			this.maxRho = Math.sqrt( width*width + height*height );
			this.maxIndexTheta=360; // precision : 1 degree by cell
			this.maxIndexRho=(int)(1+this.maxRho); // precision : 1 pixel by cell
			this.acc = new int[maxIndexTheta][maxIndexRho];
			if(this.acc == null) return false;
		}
		
		return true;
	}
	
	private void _vote(int x,int y) {
		// use origin = center of the image
		x-=iWidth/2;	y-=iHeight/2;

		// for each theta value
		for(int indexTheta=0; indexTheta<maxIndexTheta; indexTheta++) {
			double theta = ((double)indexTheta/maxIndexTheta)*Math.PI;

			// compute corresponding rho value
			double rho = x*Math.cos(theta) + y*Math.sin(theta);

			// rho -> index
			int indexRho   = (int) (0.5 + (rho/this.maxRho + 0.5)*this.maxIndexRho );

			// increment accumulator
			acc[indexTheta][indexRho]++;
		}
	}

	public boolean detect(final Buffer8I image, final int iMinAcc, final int iMinSegmentSize, ArrayList<Segment2D> results)
	{
		int width=image.getWidth();
		int height=image.getHeight();
		short buffer[]=image.getBuffer();
		
		results.clear();
		
		if(!createHoughAccumulator(width, height)) return false;
		
		int idx=0;
		for(int h=0; h<height; h++)
		{
			for(int w=0; w<width; w++, idx++)
			{
				if(buffer[idx]>0)
				{
					_vote(w, h);
				}
			}
		}
		
		/*
		 * find better lines in acc !
		 */
		for(int r=0;r<maxIndexRho;r++)
		{
			for(int t=0;t<maxIndexTheta;t++)
			{
				if (acc[t][r]<iMinAcc) continue;
				
				// indexes -> (rho,theta)
				double rho   = ((double)r/this.maxIndexRho - 0.5)*this.maxRho;
				double theta = ((double)t/this.maxIndexTheta)*Math.PI;

				if(Math.sin(theta)!=0) {
					LineSpace line = new LineSpace();
					
					line.acc = acc[t][r];
					
					line.rho = rho;
					line.theta = theta;
					
					line.a = -Math.cos(line.theta)/Math.sin(line.theta);
					line.b = line.rho/Math.sin(line.theta)+iHeight/2-line.a*iWidth/2; // use origin = (0,0)
					
					detectedLines.add(line);
				}
			}
		}
		if(detectedLines.isEmpty()) return false;
		
		/** TODO !
		 * use them to extract segment (take slope... check each pixel)
		 */
		for(LineSpace line : detectedLines)
		{
			
		}

		return false;
	}
}

